package com.leador.map.location;

import android.location.LocationManager;

import com.leador.map.location.util.Utils;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 *
 * 缓存管理
 */
public class Cache {
    private static Cache instance = null;
    private Hashtable<String, Item> htCache = new Hashtable<String, Item>();
    private long lLastCache = 0l;

    private Cache() {
        //
    }

    /**
     * 获取Cache实例
     *
     * @return LocationCache
     */
    public static Cache getInstance() {
        if (instance == null) {
            instance = new Cache();
        }
        return instance;
    }

    /**
     * 计算俩数组的相似性
     *
     * @param daA
     * @param daB
     * @return double
     */
    private static double calSimi(double[] daA, double[] daB) {
        double dSumAB = 0d;
        double dSumA = 0d;
        double dSumB = 0d;
        for (int i = 0; i < daA.length; i++) {
            dSumA += daA[i] * daA[i];
            dSumB += daB[i] * daB[i];
            dSumAB += daA[i] * daB[i];
        }
        return dSumAB / (Math.sqrt(dSumA) * Math.sqrt(dSumB));
    }

    /**
     * 将定位结果写入缓存
     *
     * @param strKey
     * @param locationInfo
     * @param sbNb
     * @return 无
     */
    public void add(String strKey, LocationInfo locationInfo, StringBuilder sbNb) {
        if (!Const.bUseCache) {
            resetCache();
            return;
        }
        if (!itemFine(strKey, locationInfo)) {
            Utils.writeCat("illegal add loc cache");
            return;
        }
        if (locationInfo.getType().equals("cache")) {
            Utils.writeCat("cache loc do not add again");
            return;
        }
        if (needReset()) {
            Utils.writeCat("loc cache need reset");
            resetCache();
        }
        lLastCache = Utils.getTime();
        Item item = new Item();
        locationInfo.setType("cache");
        item.setLocationInfo(locationInfo);
        item.setNb(sbNb.toString());
        htCache.put(strKey, item);
        Utils.writeCat("put new loc cache");
    }

    /**
     * 从缓存中获取定位结果
     *
     * @param strKey 定位Key
     * @param sbNb
     * @return 获取到的定位结果，没有找到则返回null
     */
    public LocationInfo get(String strKey, StringBuilder sbNb) {
        if (!Const.bUseCache) {
            resetCache();
            return null;
        }
        if (strKey.indexOf("#" + LocationManager.GPS_PROVIDER) != -1) {
            return null;
        }
        if (needReset()) {
            Utils.writeCat("loc cache need reset");
            resetCache();
            return null;
        }
        Utils.writeCat("get loc from cache");
        Item item = null;
        String strCacheType = "";
        if (strKey.indexOf("#cellwifi") != -1) {
            item = getSimiCache(sbNb, "#cellwifi");
            if (item != null) {
                strCacheType = "cache found#cellwifi";
            } else {
                strCacheType = "cache not found";
            }
        } else if (strKey.indexOf("#wifi") != -1) {
            item = getSimiCache(sbNb, "#wifi");
            if (item != null) {
                strCacheType = "cache found#wifi";
            } else {
                strCacheType = "cache not found";
            }
        } else if (strKey.indexOf("#cell") != -1) {
            item = htCache.get(strKey);
            if (item != null) {
                strCacheType = "cache found#cell";
            } else {
                strCacheType = "cache not found";
            }
        }
        Utils.writeCat(strCacheType);
        return item == null ? null : item.getLocationInfo();
    }

    /**
     * 检查缓存是否需要重置
     *
     * @return boolean
     */
    public boolean needReset() {
        boolean bReset = false;
        long lCacheTime = Utils.getTime() - lLastCache;
        if (lLastCache == 0l) {
            //
        } else if (htCache.size() > Const.iMaxCache) {
            bReset = true;
        } else if (lCacheTime > Const.lMaxCache) {
            bReset = true;
        }
        return bReset;
    }

    /**
     * 检查将写入缓存的定位结果的有效性
     *
     * @param strKey
     * @param locationInfo
     * @return boolean
     */
    public boolean itemFine(String strKey, LocationInfo locationInfo) {
        if (strKey == null || locationInfo == null) {
            return false;
        }
        boolean bFine = true;
        if (strKey.indexOf("#" + LocationManager.NETWORK_PROVIDER) == -1) {
            bFine = false;
        } else if (locationInfo.getLon() == 0d) {
            bFine = false;
        }
        return bFine;
    }

    /**
     * 重置缓存
     *
     * @return 无
     */
    public void resetCache() {
        lLastCache = 0l;
        htCache.clear();
        Utils.writeCat("reset loc cache");
    }

    /**
     * 获取相似缓存结果
     *
     * @param sbNb
     * @param strKeyType
     * @return Item
     */
    private Item getSimiCache(StringBuilder sbNb, String strKeyType) {
        Item itemResult = null;
        Hashtable<String, String> htA = new Hashtable<String, String>();
        Hashtable<String, String> htB = new Hashtable<String, String>();
        Hashtable<String, String> htJoin = new Hashtable<String, String>();
        Set<String> setJoin = null;
        double[] daA = null;
        double[] daB = null;
        Iterator iterCache = htCache.entrySet().iterator();
        while (iterCache.hasNext()) {
            Map.Entry entry = (Map.Entry) iterCache.next();
            String strCacheKey = (String) entry.getKey();
            Item item = (Item) entry.getValue();
            // Utils.writeCat("A#", item.getNb());
            if (item.getNb().length() < 1 || sbNb.length() < 1) {
                Utils.writeCat("nb info is empty, continue");
                continue;
            } else if (strCacheKey.indexOf(strKeyType) == -1) {
                Utils.writeCat("key type not match, continue");
                continue;
            }
            // Utils.writeCat("B#", sbNb.toString());
            if (sameAccessWifi(item.getNb(), sbNb)) {
                Utils.writeCat("same access wifi, break");
                itemResult = item;
                break;
            }
            setNbInfo(item.getNb(), htA);
            setNbInfo(sbNb.toString(), htB);
            htJoin.clear();
            for (String strKey : htA.keySet()) {
                htJoin.put(strKey, "");
            }
            for (String strKey : htB.keySet()) {
                htJoin.put(strKey, "");
            }
            setJoin = htJoin.keySet();
            daA = new double[setJoin.size()];
            daB = new double[setJoin.size()];
            int intI = 0;
            Iterator<String> iter = setJoin.iterator();
            while (iter.hasNext()) {
                String str = (String) iter.next();
                daA[intI] = htA.containsKey(str) ? 1d : 0d;
                daB[intI] = htB.containsKey(str) ? 1d : 0d;
                intI++;
            }
            setJoin.clear();
            double dSim = calSimi(daA, daB);
            Utils.writeCat("simi is:", dSim);
            if (dSim > Const.fMinCacheSimi) {
                itemResult = item;
                break;
            }
        }
        setJoin = null;
        daA = null;
        daB = null;
        htA.clear();
        htA = null;
        htB.clear();
        htB = null;
        htJoin.clear();
        htJoin = null;
        return itemResult;
    }

    /**
     * 判断主WIFI是否相同
     *
     * @param String
     * @param StringBuilder
     * @return boolean
     */
    private boolean sameAccessWifi(String strNbA, StringBuilder sbNbB) {
        int iIndexA = strNbA.indexOf(",access");
        if (iIndexA == -1 || iIndexA < 17) {
            return false;
        }
        int iIndexB = sbNbB.indexOf(",access");
        if (iIndexB == -1) {
            return false;
        }
        String str = strNbA.substring(iIndexA - 17, iIndexA);
        return sbNbB.toString().indexOf(str + ",access") != -1;
    }

    /**
     * @param strNbInfo
     * @param ht
     * @return 无
     */
    private void setNbInfo(String strNbInfo, Hashtable<String, String> ht) {
        ht.clear();
        String[] sa = strNbInfo.split("#");
        for (String str : sa) {
            if (str.length() > 0) {
                ht.put(str, "");
            }
        }
        sa = null;
    }

    /**
     * CACHE的ITEM类
     *
     * @param 无
     * @return 无
     */
    private class Item {
        private LocationInfo locationInfo = null;
        private String nb = null;

        public LocationInfo getLocationInfo() {
            return locationInfo;
        }

        public void setLocationInfo(LocationInfo locationInfo) {
            this.locationInfo = locationInfo;
        }

        public String getNb() {
            return nb;
        }

        public void setNb(String nb) {
            this.nb = nb.replace("##", "#");
        }
    }
}